home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / blix / blixserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.2 KB  |  469 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*_______________________________________________________________________
  18.  |
  19.  | blixserver.c - server side of the world highscore for blix
  20.  |
  21.  | 
  22.  | this is one program that needs to run on a server. It is
  23.  | not a bullet proof program in the sense that it produces
  24.  | nice warningmessages when you install it wrong, nor does
  25.  | it produce any logging of the access done to this server.
  26.  | 
  27.  | to install make a user with name blix;
  28.  | o compile the serverprogram with
  29.  |   cc -O -o blixserver blixserver.c blixscore_io.c
  30.  |   strip blixserver
  31.  | o copy the executable blixserver to ~blix/bin/blixserver
  32.  | o make a directory ~blix/scores (owned by user blix, and writable
  33.  |   by blix)
  34.  | o adding a line in two files
  35.  |   ==> /etc/services
  36.  |     blix 8181/tcp    # blix highscore server
  37.  |   ==> /etc/inetd.conf (or /usr/etc/inetd.conf)
  38.  |    blix stream tcp nowait blix /usr/people/blix/bin/blixserver blixserver
  39.  |                           ^^^^ 
  40.  |                             | the user blix has write permission to 
  41.  |                 the directory with the scores.
  42.  |
  43.  | o to get things working do a killall -HUP inetd
  44.  |
  45.  | I have defined BLIXIMAGE to be
  46.  | <img src="http:/www.sgi.com/images/blix.gif">
  47.  | and include a gif image; if you don't want it,
  48.  | simply define BLIXIMAGE as "", otherwise install blix.gif
  49.  | in the approriate directory.
  50.  | This is only used when using html on the 8181 port to see
  51.  | the highscores.
  52.  |
  53.  | See below for the description of the main routine.
  54.  |  
  55.  |  (c) 1994 Frans van Hoesel, hoesel@chem.rug.nl
  56.  |               Xtreme Graphics Software
  57. */
  58.  
  59. #define SCOREDIR "/usr/people/blix/scores"
  60. #define LOGFILE "/usr/people/blix/log"
  61. #define PASSFILE "/usr/people/blix/password"
  62. #define BLIXIMAGE "<img src=\"http://www.sgi.com/images/blix.gif\" alt=\"Blix Highscore\" >"
  63.  
  64. #include <unistd.h>
  65. #include <sys/types.h>
  66. #include <sys/stat.h>
  67. #include <fcntl.h>
  68. #include <stdlib.h>
  69. #include <stdio.h>
  70. #include <string.h>
  71. #include <errno.h>
  72. #include <malloc.h>
  73.  
  74. #include "blixscore_io.h"
  75.  
  76. /* don't define DEBUG in the real production, because the file
  77.  * used for logging doesn't use file locking.
  78.  */
  79. /*
  80.  * #define DEBUG
  81.  */
  82.  
  83. #define DEBUG
  84.  
  85. typedef struct {
  86.     unsigned short    imagic;
  87.     unsigned short     type;
  88.     unsigned short     dim;
  89.     unsigned short     xsize;
  90.     unsigned short     ysize;
  91.     unsigned short     zsize;
  92. } IMAGE;
  93. #define IMAGIC     0732
  94.  
  95. static scorelist_t worldlist;
  96.  
  97.  
  98. /*__________________________________________________________________
  99.  |
  100.  | main - the tricky part :-)
  101.  |
  102.  | The idea is to maintain one file with all kinds of info, but which
  103.  | has a unique sequence number (worldlist.id); whenever a new
  104.  | highscore is accepted, the id is incremented. The game itself
  105.  | caches all the info on a local disk so there is only some
  106.  | significant network traffic when something changes, which is
  107.  | very unlikely after a while. Also when a user has just installed
  108.  | the game (or otherwise deleted the cached data) some traffic
  109.  | is going on. It is never much data: just the list of scores
  110.  | and the images (which are never larger than 100 x 100).
  111.  | Only the new images that are not in the users cache are send.
  112.  |
  113.  | because the number of requests for the worldlist.id is stored
  114.  | too, the short file with the scores must be rewritten after
  115.  | each request. No big problem.
  116.  | Images are stored in seven separate RGB files, indentified by the sequence
  117.  | number and an extension '.world'. Only the five images with
  118.  | the highest sequence number need to be stored. Normally all the
  119.  | others are removed automatically.
  120.  |
  121. */
  122.  
  123.  
  124. #ifdef DEBUG
  125. FILE *logfile;
  126. char time_string[30];
  127.  
  128. void get_time(void) {
  129.     time_t t;
  130.  
  131.     t=time(NULL);
  132.     cftime(time_string, "%D %R ", &t);
  133. }
  134. #endif
  135. #define serverout 1
  136. #define serverin 0
  137.  
  138. int main() {
  139.  
  140.     int f = 0;
  141.     char cmd[5];
  142.     char tmpstr[256];
  143.     char passwd[9];
  144.     long your_id;
  145.     long your_score;
  146.     long yoursize;
  147.     long your_addr;
  148.     char your_name[128];
  149.     char your_host[128];
  150.     char *yourimage;
  151.     long imagenum;
  152.     int i;
  153.     int img;
  154.     struct stat buf;
  155.     IMAGE *image;
  156.     char *mark;
  157.     char *full;
  158.     
  159. #   ifdef DEBUG
  160.     logfile = fopen(LOGFILE, "a+");
  161.     get_time();
  162. #   endif
  163.     
  164.     if (read_data(0, cmd, -4) != 4) {
  165.     return -1;
  166.     }
  167.     cmd[4] = '\0';
  168. #   ifdef DEBUG
  169.     fprintf(logfile, "\n%s: %s\n", time_string, cmd);
  170. #   endif
  171.  
  172.  
  173.     if (strcmp(cmd, "GSCR") == 0) {
  174.     /* get score */
  175.     if (read_data(serverin, &your_id, 4) != 4) return -1;
  176.     f = openscore(SCOREDIR "/worldscore", 30);
  177.     if (f == -1) {
  178. #        ifdef DEBUG
  179.         fprintf(logfile, "%s: open local worldscore failed\n", time_string);
  180. #        endif
  181.         return -1;
  182.     }
  183.      readscore(f, &worldlist);
  184. #    ifdef DEBUG
  185.         fprintf(logfile, "%s: your id is %d; my id is %d\n", time_string,
  186.         (int) your_id, (int) worldlist.id);
  187. #    endif
  188.     worldlist.game++;
  189.     writescore(serverout, &worldlist);
  190. #    ifdef DEBUG
  191.         fprintf(logfile, "%s: did send worldscore to you; bye\n", time_string);
  192. #    endif
  193.     lseek(f, 0, SEEK_SET);
  194.     writescore(f, &worldlist);
  195.     close(f);
  196.     return 0;
  197.  
  198.  
  199.  
  200.  
  201.     } else if (strcmp(cmd, "GIMG") == 0) {
  202.     /* get image */
  203.     if (read_data(serverin, &imagenum, 4) != 4) return -1;
  204. #    ifdef DEBUG
  205.         fprintf(logfile, "%s: requested image %d\n",
  206.             time_string, (int)imagenum);
  207. #    endif        
  208.     sprintf(tmpstr, SCOREDIR "/%d.world", (int) imagenum);
  209.     img = open(tmpstr, O_RDONLY);
  210.     yoursize = 0;
  211.     if (img >= 0 && fstat(img, &buf) >= 0) {
  212.         yoursize = buf.st_size;
  213.         sprintf(tmpstr,"/%d.world", (int) imagenum);
  214.         writestr(serverout, tmpstr);
  215.     } else {
  216.         writestr(serverout, ""); 
  217.     }
  218.     write_data(serverout, &yoursize, sizeof(yoursize));
  219.     if (yoursize != 0) {
  220.         yourimage = (char *)malloc(yoursize);
  221.         read_data(img, yourimage, -yoursize);
  222.         if (write_data(serverout, yourimage, -yoursize) != yoursize) {
  223. #        ifdef DEBUG
  224.         fprintf(logfile, "%s: sending image '%s' failed\n",
  225.             time_string, tmpstr);
  226. #        endif
  227.         return -1;
  228.         }
  229.         free(yourimage);
  230.     }
  231.     if (img >= 0) {
  232.         close(img);
  233.     }
  234. #    ifdef DEBUG
  235.         fprintf(logfile, "%s: did send you image %d; bye\n",
  236.             time_string, (int) imagenum);
  237. #    endif
  238.     return 0;
  239.  
  240.  
  241.  
  242.  
  243.     } else if (strcmp(cmd, "PSCR") == 0) {
  244.     /* put score
  245.      * user thinks the highscore is beaten so
  246.      * the score + info + image is being received
  247.      */
  248.     if (read_data(0, &your_score, sizeof(long)) < 0) return -1;
  249.     if (readstr(0, your_name) < 0) return -1;
  250.     your_name[47] = '\0';
  251.     if (readstr(0, your_host) < 0) return -1;
  252.     your_name[47] = '\0';
  253.     if (read_data(0, &your_addr, sizeof(long)) < 0) return -1;
  254. #    ifdef DEBUG
  255.         fprintf(logfile, "%s: your address is %d.%d.%d.%d\n", time_string,
  256.             (int) (your_addr>>24) & 0xff, ((int) your_addr>>16) & 0xff,
  257.             (int) (your_addr>>8) & 0xff, (int) your_addr & 0xff);
  258. #    endif
  259.     if (read_data(0, &yoursize, sizeof(long)) < 0) return -1;
  260. #    ifdef DEBUG
  261.         fprintf(logfile, "%s: your image size is %d\n",
  262.             time_string, (int) yoursize);
  263. #    endif
  264.     if (yoursize != 0) {
  265.         yourimage = (char *)malloc(yoursize);
  266.         if (read_data(0, yourimage, -yoursize) != yoursize) {
  267. #        ifdef DEBUG
  268.             fprintf(logfile, "%s: failed to read image\n", time_string);
  269. #        endif
  270.         return -1;
  271.         }
  272.     }
  273.     /* ok got all the data; now compare it with the
  274.      * data already in the file; and update as needed
  275.      */
  276.     if (your_score % 5 != 0)    /* someone cheated */
  277.         return -1;
  278.     f = openscore(SCOREDIR "/worldscore", 30);
  279.     if (f == -1) {
  280. #        ifdef DEBUG
  281.         fprintf(logfile, "%s: failed to open local worldscore\n",
  282.             time_string);
  283. #        endif
  284.         return -1;
  285.     }
  286.     readscore(f, &worldlist);
  287.     if (worldlist.scores[6] >= your_score) {
  288. #        ifdef DEBUG
  289.         fprintf(logfile, "%s: worldscore %d higher than yours\n",
  290.             time_string, (int) worldlist.scores[6]);
  291. #        endif
  292.         return 0;
  293.     }
  294.     /* the high score list records the seven persons
  295.      * with the highest scores, not the seven highest scores.
  296.      * This is to get more variation on your screen:-)
  297.      */
  298.     i = 6;
  299.     for (i=0; i< 6; i++) {
  300.         if (worldlist.addrs[i] == your_addr && 
  301.             strcmp(worldlist.names[i], your_name) == NULL) {
  302.         break;
  303.         }
  304.     }
  305.     while (i > 0 && (worldlist.scores[i-1] < your_score  || 
  306.         (worldlist.scores[i] == your_score &&
  307.           (worldlist.addrs[i] != your_addr ||
  308.            strcmp(worldlist.names[i], your_name) != NULL)
  309.         ))) {
  310.         strcpy(worldlist.names[i], worldlist.names[i-1]);
  311.         strcpy(worldlist.hosts[i], worldlist.hosts[i-1]);
  312.         strcpy(worldlist.images[i], worldlist.images[i-1]);
  313.         worldlist.scores[i] = worldlist.scores[i-1];
  314.         worldlist.addrs[i] = worldlist.addrs[i-1];
  315.         i--;
  316.     }
  317.     if (worldlist.scores[i] < your_score || 
  318.         (worldlist.scores[i] == your_score &&
  319.           (worldlist.addrs[i] != your_addr ||
  320.            strcmp(worldlist.names[i], your_name) != NULL)
  321.         )) {
  322. #        ifdef DEBUG
  323.         fprintf(logfile, "%s: you are at place %d with %d points\n",
  324.             time_string, i+1, (int) your_score);
  325. #        endif
  326.         worldlist.id++;
  327.         if (*(worldlist.images[i]) != '\0') {
  328.         unlink(worldlist.images[i]);
  329.         }
  330.         strcpy(worldlist.names[i], your_name);
  331.         strcpy(worldlist.hosts[i], your_host);
  332.         worldlist.scores[i] = your_score;
  333.         worldlist.addrs[i] = your_addr;
  334.         if (yoursize > 0) {
  335.         image = (IMAGE *) yourimage;
  336.         if ( image->imagic != IMAGIC || 
  337.             image->xsize > 100 || image->ysize > 100) {
  338.             /* reject this image */
  339.             *tmpstr = '\0';
  340.         } else {
  341.             sprintf(tmpstr, SCOREDIR "/%d.world", (int) worldlist.id);
  342.             img = open(tmpstr, O_WRONLY | O_CREAT, 0666);
  343.             if (img == -1) {
  344. #            ifdef DEBUG
  345.                 fprintf(logfile, "%s: failed to open local image '%s'\n",
  346.                     time_string, tmpstr);
  347. #                endif
  348.             *tmpstr = '\0';
  349.             } else {
  350.             write_data(img, yourimage, -yoursize);
  351.             close(img);
  352.             }
  353.         }
  354.         } else {
  355.         *tmpstr = '\0';
  356.         }
  357.         tmpstr[255] = '\0';
  358.         strcpy(worldlist.images[i],tmpstr);
  359.         lseek(f, 0, SEEK_SET);
  360.         writescore(f, &worldlist);
  361. #        ifdef DEBUG
  362.         fprintf(logfile, "%s: did write local worldscore; bye\n",
  363.             time_string);
  364. #        endif
  365.         close(f);
  366.         cleanup_images(&worldlist, SCOREDIR, "world");    
  367.         return 1;
  368.     }
  369.     return 0;
  370.  
  371.  
  372.  
  373.     } else if (strcmp(cmd, "RSCR") == 0) {
  374.     /* reset score */
  375.     /* this feature  allows the author of the game to reset the
  376.      * score, if he feels it should be, because someone
  377.      * did cheat very badly.
  378.      */
  379.     gets(tmpstr);
  380.     puts("send password:");
  381.     fflush(stdout);
  382.     gets(tmpstr);
  383.     f = open(PASSFILE, O_RDONLY);
  384.     if (f < 0) {
  385.         puts("could not open password file");
  386.         return -1;
  387.     }
  388.     read(f, passwd, 8);
  389.     close(f);
  390.     if (strncmp(passwd, tmpstr, 8) != NULL) {
  391.         puts("reset command refused");
  392.         return -1;
  393.     }
  394. #    ifdef DEBUG
  395.         fprintf(logfile, "%s: accepted reset command\n", time_string);
  396. #    endif
  397.     f = openscore(SCOREDIR "/worldscore", 30);
  398.     readscore(-1, &worldlist);
  399.     worldlist.game = 2;
  400.     worldlist.id = 2;
  401.     writescore(f, &worldlist);
  402.     close(f);
  403.     puts("reset score done; bye");
  404.     return 0;    
  405.     
  406.     
  407.     } else if (strncmp(cmd,"GET",3) == 0) {
  408.     /* html request */
  409.     if (fgets(tmpstr, 254, stdin) == NULL) {
  410.             return -1;
  411.     }
  412.     tmpstr[255] = '\0';
  413.     full = strstr(tmpstr, "full");
  414.     mark = strstr(tmpstr, "HTTP/1.0");
  415.     if (mark != NULL) {
  416.         /* this is HTTP/1.0 protocol, so keep reading from the socket
  417.          * until a blank line is found */
  418.         while(fgets(tmpstr, 254, stdin) != NULL && *tmpstr != '\0'
  419.             && *tmpstr != '\n' && *tmpstr != '\r' )
  420.             ; /* do nothing */
  421.     }
  422.     puts("<title>Blix world highscores</title>");
  423.     puts(BLIXIMAGE "<p><br><br>");
  424.     f = openscore(SCOREDIR "/worldscore", 30);
  425.     readscore(f, &worldlist);
  426.     close(f);
  427.     printf("Number of users that played the game: %d\n",
  428.         (int) worldlist.game);
  429.     if (full != NULL)
  430.         printf("<br>Number of updates to this highscore: %d\n",
  431.             (int) worldlist.id);
  432.     puts("<p><br>These are the wizards of blix:<p><dl><dt><dl>");
  433.     for (i=0; i< 7; i++) {
  434.         if (worldlist.names[i] != NULL) {
  435.         printf("<dt><b>%s</b>", worldlist.names[i]);
  436.         if (worldlist.hosts[i] != NULL) {
  437.             printf(" (%s)", worldlist.hosts[i]);
  438.         }
  439.         printf("<dd><b>%d</b> points\n", (int) worldlist.scores[i]);
  440.         if (full != NULL) {
  441.             printf("<br>Address %d.%d.%d.%d\n",
  442.                 (int)(worldlist.addrs[i]>>24) & 0xff,
  443.                 (int)(worldlist.addrs[i]>>16) & 0xff,
  444.                 (int)(worldlist.addrs[i]>>8) & 0xff,
  445.                  (int)worldlist.addrs[i] & 0xff);
  446.             if (worldlist.images[i] == NULL ||
  447.                 *(worldlist.images[i]) == '\0') {
  448.             printf("<br>no image available\n");
  449.             } else {
  450.             printf("<br>image %s\n",
  451.                 strrchr(worldlist.images[i], '/') +1);
  452.             }
  453.         }
  454.         }
  455.     }
  456.     puts("</dl></dl><p><br><i>BLIX </i> is a game written by Frans van Hoesel");
  457.     puts(" for use on fast SGI machines.<p>");
  458.     puts("He can be reached at hoesel@chem.rug.nl<p>");
  459.     puts("Xtreme Graphics Software");
  460.     
  461.  
  462.  
  463.     } else {
  464.     /* rubbish command */
  465.     return -1;
  466.     }
  467.     return 0;
  468. }
  469.